package com.dt.common.validation;

import java.util.concurrent.ConcurrentHashMap;

import com.dt.common.validation.exception.BuildingException;
import com.dt.common.validation.impl.AnnotationDefinitionReader;
import com.dt.common.validation.impl.DefaultValidator;
import com.dt.common.validation.impl.JsonDefinitionReader;
import com.dt.common.validation.impl.ObjectValidationDefinition;
import com.dt.common.validation.impl.DefaultRuntimeConfiguration;

/**
 * 从configuration中构造出validator。
 * <p>
 * 由于构造validator需要扫描注解和json配置文件，耗时较长，factory具有缓存功能。
 * 根据ValidatorIdentity标识唯一validator。ValidatorFacotry最好作为单例由spring注入。
 * <p>
 * ValidatorFacotry为线程安全的。
 * 
 * @author wangfeng
 *
 */
public class ValidatorFacotry {
	private ConcurrentHashMap<ValidatorIdentity, ObjectValidationDefinition> cache = new ConcurrentHashMap<>();

	public Validator build(ValidatorConfiguration configuration) {
		final ValidatorIdentity id = config2Indentity(configuration);
		ObjectValidationDefinition objectValidationDefinition = cache.get(id);
		if (objectValidationDefinition == null) {
			objectValidationDefinition = readDefinition(id, configuration);

			cache.putIfAbsent(id, objectValidationDefinition);
		}
		DefaultValidator validator = new DefaultValidator(new DefaultRuntimeConfiguration(configuration),
				objectValidationDefinition);

		return validator;
	}

	private ValidatorIdentity config2Indentity(ValidatorConfiguration configuration) {
		return new ValidatorIdentity(configuration.getMetaClass().getName(),
				configuration.getOverridedDefinitionResource());
	}

	private ObjectValidationDefinition readDefinition(ValidatorIdentity id, ValidatorConfiguration configuration) {
		if (configuration.getClass() == null) {
			throw new BuildingException("meta class is null");
		}

		AnnotationDefinitionReader reader = new AnnotationDefinitionReader();
		ObjectValidationDefinition definitions = reader.read(id, configuration);

		if (configuration.getOverridedDefinitionResource() != null
				&& !configuration.getOverridedDefinitionResource().isEmpty()) {

			JsonDefinitionReader jsonReader = new JsonDefinitionReader();
			definitions.merge(jsonReader.read(id, configuration));
		}

		return definitions;
	}

}
